using IQIGame.Onigao.Framework;
using IQIGame.Onigao.Framework.Serialization;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using IQIGame.Onigao.Logic;
using UnityEditor;

namespace IQIGame.Onigao.GamePlay.Editors
{
    public partial class LevelServiceBlackboard
    {
        public const string ServicePrefabPath = "Assets/EditorConfig/LevelConfig/LevelServiceConfig/ServicePrefab.bytes";
        public const string ExecutionPrefabPath = "Assets/EditorConfig/LevelConfig/LevelServiceConfig/ExecutionPrefab.bytes";

        private List<EditorLevelServicePrefabSource> servicePrefab = new List<EditorLevelServicePrefabSource>();
        private List<EditorLevelServiceExecPrefabSource> exectuionPrefab = new List<EditorLevelServiceExecPrefabSource>();

        private Dictionary<string, string> servicePrefabPathCache = new Dictionary<string, string>();
        private Dictionary<string, string> executionPrefabPathCache = new Dictionary<string, string>();
        
        public void AddServicePrefab(EditorLevelServicePrefabSource rServiceSource)
        {
            this.servicePrefab.Add(rServiceSource);
        }

        public void AddExectuionPrefab(EditorLevelServiceExecPrefabSource rExectuionSource)
        {
            this.exectuionPrefab.Add(rExectuionSource);
        }

        #region Prefab
        
        public void ExportPrefab(string graphPath, bool refresh)
        {
            var rServiceList = new List<EditorLevelServicePrefabSource>();

            if (File.Exists(ServicePrefabPath))
            {
                var rByteBuf = new ByteBuf(File.ReadAllBytes(ServicePrefabPath));
                rServiceList = rByteBuf.DeSerializeList<EditorLevelServicePrefabSource>();
            }
            if (this.servicePrefab.Count > 0)
            {
                this.servicePrefab.RemoveAll((x) => string.IsNullOrEmpty(x.key));
                foreach (var rService in this.servicePrefab)
                {
                    rService.prefabPath = graphPath;
                    var nOldIndex = rServiceList.FindIndex((x) => x.key == rService.key);
                    if (nOldIndex == -1)
                    {
                        rServiceList.Add(rService);
                    }
                    else
                    {
                        rServiceList[nOldIndex] = rService;
                    }
                }
                var _buf = new ByteBuf();
                SerializeByteBufUtil.SerializeList(_buf, rServiceList);
                File.WriteAllBytes(ServicePrefabPath, _buf.Bytes);
            }

            var rExecutionList = new List<EditorLevelServiceExecPrefabSource>();
            if (File.Exists(ExecutionPrefabPath))
            {
                var rByteBuf = new ByteBuf(File.ReadAllBytes(ExecutionPrefabPath));
                rExecutionList = rByteBuf.DeSerializeList<EditorLevelServiceExecPrefabSource>();
            }
            if (this.exectuionPrefab.Count > 0)
            {
                this.exectuionPrefab.RemoveAll((x) => string.IsNullOrEmpty(x.key));
                foreach (var rPrefab in this.exectuionPrefab)
                {
                    bool bInNesting = false;
                    // 检查预设嵌套，不允许
                    for (int i = 0; i < rPrefab.executions.Count; i++)
                    {
                        var rEx = rPrefab.executions[i];
                        if (rEx.executionType == (int)ServiceExecutionType.Prefab)
                        {
                            bInNesting = true;
                            break;
                        }
                    }
                    if (bInNesting)
                    {
                        LogGame.LogError($"执行预设【{rPrefab.key}】存在嵌套，跳过此预设");
                        continue;
                    }
                    rPrefab.prefabPath = graphPath;
                    var nOldIndex = rExecutionList.FindIndex((x) => x.key == rPrefab.key);
                    if (nOldIndex == -1)
                    {
                        rExecutionList.Add(rPrefab);
                    }
                    else
                    {
                        rExecutionList[nOldIndex] = rPrefab;
                    }
                }
                var _buf = new ByteBuf();
                SerializeByteBufUtil.SerializeList(_buf, rExecutionList);
                File.WriteAllBytes(ExecutionPrefabPath, _buf.Bytes);
            }

            if (refresh)
            {
                this.Clear();
                AssetDatabase.Refresh();
            }
        }
        
        public List<string> GetPrefabList(int nType)
        {
            if (this.servicePrefabPathCache.Count <= 0 || this.executionPrefabPathCache.Count <= 0)
            {
                this.InitPrefabPathCache();
            }
            if (nType == 1)
            {
                return this.servicePrefabPathCache.Select(x => x.Key).ToList();
            }
            else
            {
                return this.executionPrefabPathCache.Select(x => x.Key).ToList();
            }
        }

        private void InitPrefabPathCache()
        {
            this.servicePrefabPathCache.Clear();
            var rPath = ServicePrefabPath;
            if (File.Exists(rPath))
            {
                var rBuf = new ByteBuf(File.ReadAllBytes(rPath));
                var rList = rBuf.DeSerializeList<EditorLevelServicePrefabSource>();
                foreach (var rConfig in rList)
                {
                    if (!string.IsNullOrEmpty(rConfig.key))
                    {
                        this.servicePrefabPathCache.Add(rConfig.key, rConfig.prefabPath);
                    }
                }
            }
            this.executionPrefabPathCache.Clear();
            var rPath2 = ExecutionPrefabPath;
            if (File.Exists(rPath2))
            {
                var rBuf = new ByteBuf(File.ReadAllBytes(rPath2));
                var rList = rBuf.DeSerializeList<EditorLevelServiceExecPrefabSource>();
                foreach (var rConfig in rList)
                {
                    this.executionPrefabPathCache.Add(rConfig.key, rConfig.prefabPath);
                }
            }
        }

        public string GetPrefabGraphPath(string prefabKey, int prefabType)
        {
            var rPathDict = prefabType == 1 ? this.servicePrefabPathCache : this.executionPrefabPathCache;
            if (rPathDict.Count <= 0)
            {
                this.InitPrefabPathCache();
            }
            if (rPathDict.TryGetValue(prefabKey, out var rPath))
            {
                return rPath;
            }
            return string.Empty;
        }

        #endregion
    }
}